package com.xxmw.transaction.common.utils.bourse;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xxmw.transaction.common.excep.service.TransactionException;
import com.xxmw.transaction.common.utils.Md5Util;
import com.xxmw.transaction.common.utils.http.HttpClientUtil;
import com.xxmw.transaction.common.utils.http.HttpHeader;
import com.xxmw.transaction.enumeration.TradeTypeEnum;
import com.xxmw.transaction.model.app.BourseApi;
import com.xxmw.transaction.model.app.BourseOrder;
import com.xxmw.transaction.vo.BalanceVo;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.*;

/**
 * https://github.com/code-biki/open-api#%E6%8E%A5%E5%8F%A3%E8%B0%83%E7%94%A8%E6%96%B9%E5%BC%8F%E8%AF%B4%E6%98%8E
 * 所有请求基于Https协议，请求头信息中content-type需要统一设置为表单格式:
 * content-type:application/x-www-form-urlencoded
 * @author luowenliang
 * @since 2020/5/20 15:41
 */
@Slf4j
public class BikiUtil {

    private static final String DOMAIN = "https://openapi.biki.com";

    /**
     * 下单路径
     */
    private static final String ORDER_PATH = "/open/api/create_order";

    /**
     * 资产信息获取路径
     */
    private static final String ACCOUNT_PATH = "/open/api/user/account";


    /**
     * 下单
     * @param api
     * @param order
     */
    public static void order (BourseApi api, BourseOrder order) {

        Map<String, String> paramMap = new TreeMap<>();

        paramMap.put("api_key", api.getAccessKey());

        String tradeType = TradeTypeEnum.getDescByValue(order.getTradeType());

        paramMap.put("side", tradeType.contains("buy") ? "BUY" : "SELL");

        //1 限价委托, 2 市价委托
        String type = tradeType.contains("market") ? "2" : "1";
        paramMap.put("type", type);

        //type=1:表示买卖数量, type=2:买则表示总价格，卖表示总个数 TODO  买则表示总价格，卖表示总个数待验证
        paramMap.put("volume", type.equals("1") ? order.getNum().stripTrailingZeros().toPlainString() :
                order.getPrice().stripTrailingZeros().toPlainString());
        if (type.equals("1")) {
            paramMap.put("price", order.getPrice().stripTrailingZeros().toPlainString());
        }
        String time = String.valueOf(System.currentTimeMillis());
        paramMap.put("symbol", order.getSymbol());
        paramMap.put("time", time);
        paramMap.put("sign", sign(paramMap, api.getSecretKey()));

        StringBuilder sb = new StringBuilder();
        paramMap.entrySet().forEach(entry -> sb.append(entry.toString()).append("&"));
        String params = sb.substring(0, sb.length() - 1);
        log.info("biki下单请求的参数为： {}", params);
        HttpHeader header = new HttpHeader();
        header.add("content-type", "application/x-www-form-urlencoded");

        String res = HttpClientUtil.post(DOMAIN + ORDER_PATH, header, params);
        log.info("BIKI下单返回结果：{}", res);

        JSONObject object = JSON.parseObject(res);
        if (object != null && object.getString("code").equals("0")) {
            JSONObject data = object.getJSONObject("data");
            order.setOutId(data.getString("order_id"));
            order.setStatus(1);
        } else {
            log.error("BIKI下单异常：{}", res);
//            throw new TransactionException("BIKI下单失败：");
            order.setStatus(7);
            order.setRemark(object.getString("msg"));
        }
    }

    private static String sign (Map<String, String> paramMap, String secretKey) {
        StringBuilder paramSb = new StringBuilder();
        paramMap.entrySet().forEach(entry -> paramSb.append(entry.getKey()).append(entry.getValue()));
        paramSb.append(secretKey);
        String signStr = paramSb.toString();
        log.error("BIKI签名字符串: {}", signStr);
        return Md5Util.encoder(signStr).toLowerCase();
    }

    /**
     * 获取账户余额
     * @param api
     * @param currency usdt、btc...
     * @return
     */
    public static BalanceVo getBalance(BourseApi api, String currency) {
        JSONArray array = getBalanceArray(api);
        return getBalanceByCurrency(array, currency);
    }

    /**
     * biki返回的数组
     * @param array
     * @param currency
     * @return
     */
    private static BalanceVo getBalanceByCurrency(JSONArray array, String currency) {
        BalanceVo balanceVo = new BalanceVo();
        for (int i =0; i < array.size(); i ++) {
            JSONObject jsonObject = array.getJSONObject(i);
            if (jsonObject.getString("coin").equals(currency)) {
                balanceVo.setAvailable(jsonObject.getBigDecimal("normal"));
                balanceVo.setFrozen(jsonObject.getBigDecimal("locked"));
                balanceVo.setTotal(balanceVo.getAvailable().add(balanceVo.getFrozen()));
                log.info("获取biki币种{}价格：{}", currency, balanceVo.toString());
                break;
            }
        }
        return balanceVo;
    }

    public static Map<String, BalanceVo> getBalance (BourseApi api, List<String> currency) {

        Map<String, BalanceVo> map = new HashMap<>(16);

        if (currency.size() <= 0) {
            return map;
        }
        JSONArray array = getBalanceArray(api);
        for (String s : currency) {
            map.put(s, getBalanceByCurrency(array, s));
        }
        return map;
    }

    public static JSONArray getBalanceArray (BourseApi api) {
        Map<String, String> paramMap = new TreeMap<>();

        paramMap.put("api_key", api.getAccessKey());
        paramMap.put("time", String.valueOf(System.currentTimeMillis()));
        paramMap.put("sign", sign(paramMap, api.getSecretKey()));

        StringBuilder sb = new StringBuilder();
        paramMap.entrySet().forEach(entry -> sb.append(entry.toString()).append("&"));
        String params = sb.substring(0, sb.length() - 1);

        String url = DOMAIN + ACCOUNT_PATH + "?" + params;
        String res = HttpClientUtil.get(url);
        JSONObject object = JSONObject.parseObject(res);
        if (object != null && object.getString("code").equals("0")) {
            JSONObject data = object.getJSONObject("data");
            //总资产 data.get("total_asset") 单位BTC
            return data.getJSONArray("coin_list");
        }
        throw new TransactionException("获取BIKI账户余额信息异常");
    }

    public static void main(String[] args) {
        BourseApi bourseApi = new BourseApi();
        bourseApi.setAccountId(3685505L);
        bourseApi.setAccessKey("f9d619945fc2be37e20ef032ecddeaf8");
        bourseApi.setSecretKey("7f68e4c945e322ef68cde1b71c59ef21");

        BourseOrder bourseOrder = new BourseOrder();
        bourseOrder.setBourse(1);
        bourseOrder.setCreated(new Date());
        bourseOrder.setStatus(0);
        bourseOrder.setSymbol("ethusdt");
        bourseOrder.setTradeType(TradeTypeEnum.BUY_LIMIT.getValue());
        bourseOrder.setNum(new BigDecimal("1"));
        bourseOrder.setPrice(new BigDecimal("150"));
        order(bourseApi, bourseOrder);
        //getBalanceArray(bourseApi);
    }
}
